package org.wu.framework.lazy.orm.database.jpa.repository.query;

import org.wu.framework.core.CamelAndUnderLineConverter;
import org.wu.framework.core.NormalUsedString;
import org.wu.framework.core.annotation.AnnotatedElementUtils;
import org.wu.framework.core.exception.RuntimeExceptionFactory;
import org.wu.framework.lazy.orm.core.persistence.conf.LazyTableEndpoint;
import org.wu.framework.lazy.orm.core.source.SqlSourceClass;
import org.wu.framework.lazy.orm.database.jpa.repository.annotation.LazyParam;
import org.wu.framework.lazy.orm.database.jpa.repository.annotation.LazyQuery;
import org.wu.framework.lazy.orm.database.jpa.repository.enums.MethodName2SQLType;
import org.wu.framework.lazy.orm.database.jpa.repository.enums.QueryType;
import org.wu.framework.lazy.orm.database.jpa.repository.support.method.JpaDynamicMethodSupportFactory;
import org.wu.framework.lazy.orm.database.lambda.stream.lambda.LazyLambdaStream;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

public class LazyQueryMetadataFactory {


    /**
     * 创建 如果方法上含有LazyQuery或者其子类注解创建 LazyQueryMetadata 对象
     *
     * @param method           执行方法
     * @param arguments        方法参数
     * @param lazyLambdaStream LazyLambdaStream 字段
     * @return LazyQueryMetadata
     */
    public static LazyQueryMetadata createLazyQueryMetadata(Method method, Object[] arguments, LazyLambdaStream lazyLambdaStream) {

        if (AnnotatedElementUtils.hasAnnotation(method, LazyQuery.class)) {
            // 获取指定注解类型
            LazyQuery lazyQuery = AnnotatedElementUtils.findMergedAnnotation(method, LazyQuery.class);
            assert lazyQuery != null;
            QueryType queryType = lazyQuery.queryType();
            String querySql = lazyQuery.value();

            Parameter[] methodParameters = method.getParameters();
            // 解析参数
            DefaultLazyParameters defaultLazyParameters = new DefaultLazyParameters();
            for (int i = 0; i < methodParameters.length; i++) {
                Parameter methodParameter = methodParameters[i];
                LazyParam annotation = methodParameter.getAnnotation(LazyParam.class);

                Object argument = arguments[i];
                if (annotation != null) {
                    defaultLazyParameters.addParameter(annotation.value(), argument);
                } else {
                    defaultLazyParameters.addParameter(CamelAndUnderLineConverter.humpToLine2(methodParameter.getName()), argument);
                }
            }
            return new DefaultLazyQueryMetadata(querySql, queryType, method, defaultLazyParameters, lazyLambdaStream);
        } else {
            RuntimeExceptionFactory.of("无法解析方法，请确定方法" + method + "是否包含指定注解@LazyQuery");
        }

        return null;
    }




    /**
     * 通过方法名创建 LazyQueryMetadata 对象
     *
     * @param method           执行方法
     * @param arguments        方法参数
     * @param lazyLambdaStream LazyLambdaStream 字段
     * @return LazyQueryMetadata
     */
    public static LazyQueryMetadata createLazyQueryMetadataByMethodName(Method method, Object[] arguments, LazyLambdaStream lazyLambdaStream) {

        if (support(method)) {
            RuntimeExceptionFactory.of("解析自定义方法名错误，当前方法含有注解@LazyQuery或者其子注解");

        } else {
            Class<?> declaringClass = method.getDeclaringClass();
            LazyTableEndpoint lazyTableEndpoint = SqlSourceClass.getInstance(declaringClass).getLazyTableEndpoint();
            String tableName = lazyTableEndpoint.getTableName();
            String methodName = method.getName();
            MethodName2SQLType name2SQLType = Arrays
                    .stream(MethodName2SQLType.values())
                    .filter(methodName2SQLType -> methodName.startsWith(methodName2SQLType.getStartMethodNamePrefix()))
                    .findFirst().get();

            QueryType queryType = name2SQLType.getQueryType();

            String querySql = JpaDynamicMethodSupportFactory.createSqlByMethod(method);

            Parameter[] methodParameters = method.getParameters();
            // 解析参数
            DefaultLazyParameters defaultLazyParameters = new DefaultLazyParameters();
            for (int i = 0; i < methodParameters.length; i++) {
                Parameter methodParameter = methodParameters[i];
                LazyParam annotation = methodParameter.getAnnotation(LazyParam.class);

                Object argument = arguments[i];
                if (annotation != null) {
                    defaultLazyParameters.addParameter(annotation.value(), argument);
                } else {
                    defaultLazyParameters.addParameter(methodParameter.getName(), argument);
                }
            }
            return new DefaultLazyQueryMetadata(querySql, queryType, method, defaultLazyParameters, lazyLambdaStream);
        }

        return null;
    }

    /**
     * 当前方式是否支持
     *
     * @param method 方法
     * @return 是否支持
     */
    public static Boolean support(Method method) {
        return AnnotatedElementUtils.hasAnnotation(method, LazyQuery.class);
    }

    /**
     * 判断是否含有xml
     *
     * @param method 方法
     * @return 是否支持
     */
    public static Boolean hasXml(Method method) {
        return false;
    }

    /**
     * 判断是否支持方法转换成sql
     *
     * @param method 方法
     * @return 判断是否支持方法转换成sql
     */
    public static Boolean supportMethodName2SQL(Method method) {
        String methodName = method.getName();
        return Arrays.stream(MethodName2SQLType.values())
                .anyMatch(methodName2SQLType -> methodName.startsWith(methodName2SQLType.getStartMethodNamePrefix()));
    }
}
